from gettext import gettext as _

import pygtk
import gtk
import gtk.glade
import gobject

import dbus
import dbus.service
import dbus.glib

import datetime

try:
	import sexy
except ImportError:
	sexy = None
try:
	import pynotify
except:
	pynotify = None

import gnomeagenda

from gnomeagenda import Keybinder
from gnomeagenda.pluginsystem import *
from gnomeagenda.ui.AgendaWindow import AgendaWindow
from gnomeagenda.ui.EditEventWindow import EditEventWindow
from gnomeagenda.ui.AgendaListView import  AgendaListView
from gnomeagenda.ui.PrefDialog import PrefDialog


class Agenda(dbus.service.Object):
	DEFAULT_KEYBINDING = "<Alt>F12"
	@dbus.service.method("org.domain.GnomeAgenda")
	def ShowMainWindow(self):
		self.window.show_window()
	@dbus.service.method("org.domain.GnomeAgenda")
	def ShowPreferences(self):
		self.settings_activate_cb(None)
	@dbus.service.method("org.domain.GnomeAgenda")
	def updateCalendars(self):
		self.appointments.updateCalendars()
	@dbus.service.method ("org.domain.GnomeAgenda", in_signature='a{sv}', out_signature='')
	def start(self,options):
		if(options['pref']):
			self.ShowPreferences()
		if(options['update']):
			self.updateCalendars()
		if self.is_running ():
			self.window.show_window()
		else:
			self.running = True
			gtk.main ()
			self.running = False


	@dbus.service.method ("org.domain.GnomeAgenda", in_signature='', out_signature='b')
	def is_running(self,):
		return self.running	
	
	def about_icon_cb(self,widget):
		"""
		About clicked
		"""
		
		self.aboutdialog.run()
		self.aboutdialog.hide()
		
		pass
		
	
	def settings_activate_cb(self,widget = None):
		"""
		Show the preference dialog
		"""
		prefs = PrefDialog(self.appointments,self)
		result = prefs.run()
		#self.window.resize(max(0,int(self.appointments.get_option('width'))),max(0,int(self.appointments.get_option('height'))))
		self.updateView()
		
		pass

	def popup_menu_cb(self,widget, button = None, time= None, data = None):
		"""
		right click on the status icon
		"""

		if(self.statusIcon.get_geometry()):
			self.popup_menu.popup(None, None, gtk.status_icon_position_menu, button, time,self.statusIcon)
		else:
			self.popup_menu.popup(None, None, None, button, time,self.statusIcon)

	def status_icon_click_cb(self,widget=None,menu=None):
		"""
		left click on the status icon
		"""
		self.window.show_window()
	
	def menu_position_func(self,menu,data):
		event = data[0]
		widget = data[1]
		x,y = int(event.x_root+1), int(event.y_root+1)

		return (x,y,True)
	def on_configure(self,widget, event):
		print event
		
	def main_button_press_event_cb(self, widget=None,event = None,data = None):
		if ((data == None and event.button == 3) or (data != None and event.button == 1)):
			self.popup_menu.popup(None, None, self.menu_position_func, event.button, event.time,(event,data))

		return True
		pass
	def main_destroy_event_cb(self,widget, data=None):
		##do not call quit() since, the window will be destroyed, and the size/position is not valid anymore
		gtk.main_quit()
	def searchBox_clear(self,widget,filterEntry):
		
		if(filterEntry.get_text() != ""):
			filterEntry.set_text("")
			self.search_entry_activate_cb(None,filterEntry)
	def search_entry_activate_cb(self,widget,filterEntry):
		"""
		Perform the search if "ENTER" was hit
		"""
		self.SearchTerm = filterEntry.get_text()
		self.updateView()
		
	def exit_activate_cb(self,widget,data = None):
		"""
		popup_menu_exit handler
		"""
		if(self.statusIcon):
			self.statusIcon.set_visible(False)
		self.saveSettings()
		gtk.main_quit()
	def saveSettings(self):
		pass
		self.appointments.set_option('width',max(0,int(self.window.get_size()[0])))
		self.appointments.set_option('height',max(0,int(self.window.get_size()[1])))
		self.appointments.set_option('hide_finished',bool(self.hide_finished))
	
	def main_delete_event_cb(self,event,data):
		"""delete event of the main window"""
		"""just hide, and stop propagating the event"""
		self.status_icon_click_cb()
		return True
	def dismiss_error_button_clicked_cb(self,widget):
		self.dismissErrors()
	def dismissErrors(self):
		self.errors_label.set_text("")
		self.appointments.clearErrors()
		self.errorPanel.hide()
		
	def updateView(self):
		"""
		update the GUI 
		"""
		print "update View"
		self.updateErrors()
		resultRows = self.appointments.search(self.SearchTerm)
		
		nextUpdateTime = self.calendar.updateView(resultRows)
		now = datetime.datetime.now()
		nr =  (nextUpdateTime - now)
		nextdraw_sec = nr.days * 86400 + nr.seconds + 1
		#print "Next redraw at %s (%s sec)" % (nextUpdateTime,nextdraw_sec)
		self.timeout_redraw = gobject.timeout_add(nextdraw_sec * 1000, self.updateView)
		
		
		pass
	def getErrors(self):
		error_text = []
		for error in self.appointments.getErrors():
			try:
				name = error[0]
			except:
				name = ""
			try:
				prov_errors = ("\n".join(error[1]))
			except:
				prov_errors = ""
			error_text.append("<b><big>%s</big></b>\n%s\n" %(name,prov_errors))
		return ("\n".join(error_text)).strip()
	def updateErrors(self):
		errors = self.getErrors()
		self.errors_label.set_markup(errors)
		if(len(errors) > 0):
			self.errorPanel.show()
		else:
			self.errorPanel.hide()
	def setBusy(self, busy = True):
		"""
		update the UI to indicate that we are currently updating...
		"""
		if(busy):
			cursor = gtk.gdk.Cursor(gtk.gdk.WATCH)
			self.progressbar.pulse()
			self.progressbar.show()
			self.do_pulse = True
			gobject.timeout_add(333, self.appointments_progress_cb)
			
		else:
			cursor = None
			self.progressbar.hide()
			self.do_pulse = False
		try:
			gdkwin = self.window.window
			if(gdkwin):
				gdkwin.set_cursor(cursor)
		except Exception,e:
			pass
		gtk.gdk.flush()
	def refresh_async(self,):
		self.appointments.updateCalendars()
	def refresh_cb(self,widget=None):
		""" refresh """
		#g_thread_create(async_lengthy_func, button, FALSE, NULL);
		self.refresh_async()

		pass
	def widget_initialized(self):
		"""
		Called at the end of init
		"""
		self.updateView()
		self.window.resize(max(0,int(self.appointments.get_option('width'))),max(0,int(self.appointments.get_option('height'))))

		screen_w, screen_h = gtk.gdk.screen_width(), gtk.gdk.screen_height()
		self.hide_finished = bool(self.appointments.get_option('hide_finished'))
		#try:
		#	self.pynotify_ok = pynotify.init(gnomeagenda.APP_NAME)
		#except:
		#	self.pynotify_ok = False
		#if(self.pynotify_ok and int(self.appointments.get_option('reminder')) > 0):
		#	gobject.timeout_add(10000, self.remind)	
	def notify(self,event):
		pass
	def remind(self,):
		"""This has to be reimplemented"""
		return
		sql = "SELECT * from Events e, Calendar c WHERE c.hidden = 0 and c.id = e.calendar_id and datetime(e.start_time) > datetime('now') and datetime(e.start_time) < datetime('now','%s minutes') order by e.start_time"
		sql = sql % self.appointments.get_option('reminder')
		toremind = self.appointments.query(sql)
		for row in toremind:
			id = row[0]
			try:
				self.notified_ids.index(id)
				exists = True
			except:
				exists = False
			if(not exists):
				n = pynotify.Notification(row[5],self.getToolipText(row))
				n.set_icon_from_pixbuf(self.app_icon)
				n.set_urgency(pynotify.URGENCY_CRITICAL)
				n.set_timeout(pynotify.EXPIRES_NEVER)
				n.show()
				self.notified_ids.append(id)
		self.timeout_alert = gobject.timeout_add(10000, self.remind)
		return False

	def sexy_searchbox_pressed(self,filterEntry,pos,button, data = None):
		if(pos == sexy.ICON_ENTRY_SECONDARY):
			if(filterEntry.get_text() != ""):
				filterEntry.set_text("")
				self.search_entry_activate_cb(None,filterEntry)	
		elif (pos == sexy.ICON_ENTRY_PRIMARY):
			#TODO: popup the filter changer
			print "sexy.ICON_ENTRY_PRIMARY"
			
			pass
	def on_filterEntry_key_pressed(self,  filterEntry, data):
		keyname = gtk.gdk.keyval_name(data.keyval)
		if keyname == "Escape":
			filterEntry.set_text("")
			self.search_entry_activate_cb(None,filterEntry)	

	def addEventBtn_activate_cb(self,t):
		print t
		print "addEventBtn_activate_cb"
		newEvtDlg = EditEventWindow(self.window,None)
		response = newEvtDlg.run()

	def bind_keybinding(self, binding):
		"""
		Actually bind keybinding
		"""
		if not self._keybinder.bind(binding):
			print "Keybinding is already in use"
			pass
		else:
			print "Successfully bound to %s" % binding
			pass
			
	def _emit_keybinding_activated(self,t,d = None, k = None):
		self.window.toggle_window()
		
	def _setup_keybinder(self):
		#self._gconf.connect("keybinding-changed", self._on_keybinding_changed)
		
		self._keybinder = Keybinder()
		keybinding = self.get_keybinding()
		if (keybinding == None or gtk.accelerator_parse(keybinding) == (0,0)):
			# Keybinding is not set or invalid, set default keybinding
			keybinding = self.DEFAULT_KEYBINDING
			self.set_keybinding(keybinding) # try to save it to Gconf
		else:
			keybinding = self.get_keybinding()
		self.bind_keybinding(keybinding)
		
		self._keybinder.connect("activated", lambda k,t: self._emit_keybinding_activated(t))
	def set_keybinding(self,	accel_name):
		self.appointments.set_option('accelerator', accel_name)
	def get_keybinding(self):
		"""
		Get keybinding
		
		@return: str
		"""
		#return self._gconf.get_keybinding()
		return self.appointments.get_option('accelerator')
	def appointments_calendars_updated_cb(self,appointments):
		"""
		called whenever the calendars were updated
		"""
		self.setBusy(False)
		self.updateView()
	def appointments_updating_calendars(self,appointments):
		self.setBusy(True)
		#it would be nice to update the status icon here as well
	def appointments_updating_tick(self,appointments,progress,time):
		while gtk.events_pending():
			gtk.main_iteration(False)	
	def appointments_progress_cb(self):
		self.progressbar.pulse()
		while gtk.events_pending():
			gtk.main_iteration(False)
		return self.do_pulse
	def appointments_updating_provider(self,appointments,providername):
		text =  providername
		self.progressbar.set_text(text)
		while gtk.events_pending():
			gtk.main_iteration(False)
	def __init__(self, appointments,bus, path, name):
		dbus.service.Object.__init__ (self, bus, path, name)
		
		self.running = False
		self.appointments = appointments
		
		self.appointments.connect('updating-calendars-finished',self.appointments_calendars_updated_cb)
		self.appointments.connect('updating-calendars-start',self.appointments_updating_calendars)
		self.appointments.connect('updating-calendars-tick',self.appointments_updating_tick)
		self.appointments.connect('updating-provider',self.appointments_updating_provider)
		
		#calendars_updated_cb
		"""window is hidden on startup"""
		#The last searched Term
		self.SearchTerm = ""
		#hide finished events
		self.hide_finished = True
		#hold the timeout-ids for refreshing/alerting
		self.timeout_refresh = -1
		self.timeout_alert = -1
		self.timeout_redraw = -1
		#stores event-ids that ahe already been notified
		self.notified_ids = []
		#Set the Glade file

		self.wTree = gtk.glade.XML(gnomeagenda.GLADEFILE)

		pixbuf = gnomeagenda.load_stock_image("x-office-calendar")
		
		gtk.window_set_default_icon(pixbuf)
		self.statusIcon = gtk.StatusIcon()
		self.statusIcon.set_from_pixbuf(pixbuf)
		self.statusIcon.set_tooltip(gnomeagenda.APP_NAME)

		self.statusIcon.connect('popup-menu', self.popup_menu_cb)
		self.statusIcon.connect('activate', self.status_icon_click_cb)
		self.statusIcon.set_visible(True)
		panel = self.wTree.get_widget("search_container")
		
		find_image = gtk.Image()
		find_image.set_from_stock(gtk.STOCK_FIND,gtk.ICON_SIZE_MENU)
			
		if sexy:
			filterEntry = sexy.IconEntry()
			filterEntry.add_clear_button()
			filterEntry.connect('icon-pressed',self.sexy_searchbox_pressed)
			filterEntry.set_icon (sexy.ICON_ENTRY_PRIMARY, find_image)
			#filterEntry.set_icon_highlight (sexy.ICON_ENTRY_PRIMARY,True)

			panel.pack_start(filterEntry)
			panel.reorder_child(filterEntry,1)
			filterEntry.show()
		else:
			hbox = gtk.HBox()

			filterChangeBtn = gtk.Button()
			
			filterEntry = gtk.Entry()
			clear_button = gtk.Button()
			i = gtk.Image()
			i.set_from_stock(gtk.STOCK_CLEAR,gtk.ICON_SIZE_MENU)

			#filterChangeBtn.add(find_image)
			#filterChangeBtn.set_focus_on_click(False)
			#filterChangeBtn.set_relief(gtk.RELIEF_NONE)
			#filterChangeBtn.set_property("can-focus",False)
			clear_button.add(i)
			clear_button.set_focus_on_click(False)
			clear_button.set_relief(gtk.RELIEF_NONE)
			clear_button.connect('clicked',self.searchBox_clear,filterEntry)
			clear_button.set_property("can-focus",False)
			#hbox.pack_start(filterChangeBtn,False)
			hbox.pack_start(filterEntry)
			hbox.pack_start(clear_button,False)
			
			panel.pack_start(hbox)
			panel.reorder_child(hbox,1)
			
			hbox.set_border_width(2)
			
			filterEntry.show()
			clear_button.show()


		filterEntry.connect('activate',self.search_entry_activate_cb,filterEntry)
		filterEntry.connect("key-press-event", self.on_filterEntry_key_pressed)

		self.window = AgendaWindow(self.statusIcon)
		
		#frame = self.wTree.get_widget("gnome-agenda-frame")
		#frame.modify_bg(frame.state,frame.style.white)

		#frame.reparent(self.window)
		#frame.set_border_width(0)
		
		panel = self.wTree.get_widget("panel")
		panel.modify_bg(panel.state,panel.style.white)

		panel.reparent(self.window)
		panel.set_border_width(0)
				
		#Connect to the signals
		self.wTree.signal_autoconnect(self)
		self.window.connect("button-press-event",self.main_button_press_event_cb)
		#the global widgets
		self.errorPanel = self.wTree.get_widget("errorPanel")
		self.popup_menu = self.wTree.get_widget("popup_menu")
		self.search_entry = self.wTree.get_widget("search_entry")
		self.errors_label = self.wTree.get_widget("errors_label")
		self.scroll_area =  self.wTree.get_widget("scroll_area")
		self.aboutdialog = self.wTree.get_widget("aboutdialog")
		self.aboutdialog.set_version(gnomeagenda.APP_VERSION)
		self.aboutdialog.set_program_name(gnomeagenda.APP_NAME)
		

		self.toggle_window_radio_btn = self.wTree.get_widget("toggle_window_radio_btn")
		self.calendar = AgendaListView()
		
		cal_viewport = self.wTree.get_widget("cal_viewport")
		cal_viewport.add(self.calendar)
						
		#self.scroll_area.get_child().add(self.calendar)
		self.scroll_area.set_size_request(1,-1)
		
		self.tooltips = gtk.Tooltips()
		##add the status icon

		self.progressbar = self.wTree.get_widget("progressbar")

		self.app_icon = gnomeagenda.load_stock_image("x-office-calendar",gtk.ICON_SIZE_DIALOG)
		#THIS HAS TO BE THE LAST LINE IN __init__
		self.widget_initialized()
		
		if(Keybinder):
			try:
				self._setup_keybinder()
			except:
				LOGGER.error("could not setup keybinder")
				print "Keybinding is not supported"
			

